package com.lx.config;

import com.lx.entity.SysUser;
import com.lx.handler.AuthLimitHandler;
import com.lx.handler.LoginSuccessHandler;
import com.lx.mapper.SysUserMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import java.util.Objects;

@Configuration
// securedEnabled = true 表示方法权限控制可以使用安全注解
// 在使用@Secured注解时，必须在现有的角色名称前加上ROLE前缀，如@Secured("ROLEADMIN"),
// 多个角色@Secured({"ROLEADMIN", "ROLEUSER"}),表示至少有其中一个才可访问

// prePostEnabled = true 表示方法权限前置注解 @PreAuthorize, @PostAuthorize启用
// jsr250Enabled = true 表示启动了JSR-250的注解支持，注解@DenyAll 拒绝所有访问，注解 @PermitAll 允许所有访问，
// 注解 @RolesAllowed({"USER", "ADMIN"})  该方法只要具有"USER", "ADMIN"任意一种权限就可以访问。这里可以省略前缀ROLE，
// 实际的权限可能是ROLEADMIN
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired(required = false)
    private SysUserMapper sysUserMapper;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 配置登陆页 会跳转到security的默认登陆页，这个没用权限限制，仍可访问其他接口
//        http.formLogin();
        // 配置登录页，跳转到指定的页面，设置不需要授权即可访问
        http.formLogin().loginPage("/login").permitAll();

        // 配置登陆成功后默认页面
        http.formLogin().defaultSuccessUrl("/").successHandler(new LoginSuccessHandler());

        // 登出授权
        http.logout().permitAll();


        // 授权配置，配置后其他接口就需要登陆后才能访问
        http
                .exceptionHandling().accessDeniedHandler(new AuthLimitHandler())
                .and()
                .authorizeRequests()
                /* 所有静态文件可以访问 */
                .antMatchers("/js/**", "/css/**", "images/**").permitAll()
                /* 所有已 /ad 开头的 广告页可以访问 */
                .antMatchers("/ad/**").permitAll()
                .anyRequest().fullyAuthenticated();
        // 授权配置，和上边的fullyAuthenticated功能基本一样，authenticated是页面如果通过登陆记住我功能，接口也可以访问
//                .anyRequest().authenticated();

    }

    @Override
    protected UserDetailsService userDetailsService() {
        return username -> {
            if (StringUtils.isBlank(username)) {
                throw new UsernameNotFoundException("用户名为空！");
            }

            SysUser sysUser = sysUserMapper.selectByUserName(username);
            if (Objects.nonNull(sysUser)) {
                return sysUser;
            }
            throw new UsernameNotFoundException("用户不存在！");
        };
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService()).passwordEncoder(new BCryptPasswordEncoder());
    }
}
